package ae.pcfc.etks.online.web.controller.nonclient.person.register;

import java.io.File;
import java.io.FileOutputStream;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Locale;
import java.util.Map;

import javassist.bytecode.DuplicateMemberException;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import javax.validation.Valid;

import org.apache.commons.io.FileUtils;
import org.apache.commons.io.FilenameUtils;
import org.apache.commons.lang.StringUtils;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.util.MultiValueMap;
import org.springframework.validation.BindingResult;
import org.springframework.web.bind.annotation.ModelAttribute;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.bind.support.SessionStatus;
import org.springframework.web.multipart.MultipartFile;
import org.springframework.web.multipart.MultipartHttpServletRequest;
import org.springframework.web.servlet.support.RequestContextUtils;
import org.springframework.web.util.WebUtils;

import ae.pcfc.etks.online.common.ConstantsCommon;
import ae.pcfc.etks.online.common.ConstantsCommon.WFProcessType;
import ae.pcfc.etks.online.common.delegate.AttachmentTypeDelegate;
import ae.pcfc.etks.online.common.delegate.NonClientPersonRegisterDelegate;
import ae.pcfc.etks.online.common.delegate.UtilityDelegate;
import ae.pcfc.etks.online.common.vo.AttachmentTypeVO;
import ae.pcfc.etks.online.common.vo.CityVO;
import ae.pcfc.etks.online.common.vo.ClientCategoryVO;
import ae.pcfc.etks.online.common.vo.ClientRoleVO;
import ae.pcfc.etks.online.common.vo.CountryVO;
import ae.pcfc.etks.online.common.vo.LabelVO;
import ae.pcfc.etks.online.common.vo.NameTitleVO;
import ae.pcfc.etks.online.common.vo.NonClientPersonVO;
import ae.pcfc.etks.online.common.vo.UploadDocumentVO;
import ae.pcfc.etks.online.common.vo.VisaTypeVO;
import ae.pcfc.etks.online.web.ConstantsAdmin;
import ae.pcfc.etks.online.web.PageType;
import ae.pcfc.etks.online.web.ViewPath;
import ae.pcfc.etks.online.web.ViewUtils;
import ae.pcfc.etks.online.web.common.Constants;
import ae.pcfc.etks.online.web.controller.BaseController;
import ae.pcfc.etks.online.web.model.NonClientCompanyRegistrationLicenseInfo;
import ae.pcfc.etks.online.web.model.NonClientPersonRegisterPersonalInfo;
import ae.pcfc.etks.online.web.util.SecurityUtils;

/**
 * Controller that handles all {@link NonClientPersonController}-related requests,
 * i.e.: all requests for /nonclient/person/register/*
 * 
 * @author Mohtisham.Salahria
 */
@Controller
@RequestMapping(ViewPath.NON_CLIENT_PERSON_REGISTER)
public class NonClientPersonController extends BaseController{

	private Map<String, String> propertyConstants;

	@Resource(name = "propertyConstants")
	public void setPropertyConstants(Map<String, String> propertyConstants) {
		this.propertyConstants = propertyConstants;
	}

	private NonClientPersonRegisterDelegate nonClientPersonRegisterDelegate;

	@Resource(name = "nonClientPersonRegisterDelegate")
	public void setNonClientPersonRegisterDelegate(NonClientPersonRegisterDelegate nonClientPersonRegisterDelegate) {
		this.nonClientPersonRegisterDelegate = nonClientPersonRegisterDelegate;
	}

	private UtilityDelegate utilityDelegate;

	@Resource(name = "utilityDelegate")
	public void setUtilityDelegate(UtilityDelegate utilityDelegate) {
		this.utilityDelegate = utilityDelegate;
	}

	private AttachmentTypeDelegate attachmentTypeDelegate;

	@Resource(name = "attachmentTypeDelegate")
	public void setAttachmentTypeDelegate(AttachmentTypeDelegate attachmentTypeDelegate) {
		this.attachmentTypeDelegate = attachmentTypeDelegate;
	}


	@ModelAttribute(ConstantsAdmin.NON_CLIENT_PERSON_REGISTER_REQUEST_MODEL_KEY)
	public NonClientPersonRegisterPersonalInfo populatePersonRegisterClientPersonalInfoModel(HttpServletRequest request,
			@RequestParam(value = "id", required = false) String id) {

		return new NonClientPersonRegisterPersonalInfo();
	}

	@ModelAttribute(ConstantsAdmin.TITLE_LIST_REQUEST_MODEL_KEY)
	public List<LabelVO> populateTitlesListModel() {

		List<LabelVO> labelList = new ArrayList<LabelVO>();

		LabelVO labelVO;
		List<NameTitleVO> nametitleVOs = utilityDelegate.getNameTitle();

		for (NameTitleVO nametitleVO : nametitleVOs) {
			labelVO = getMapper().map(nametitleVO, LabelVO.class);
			labelList.add(labelVO);
		}

		return labelList;
	}
	
	@ModelAttribute(ConstantsAdmin.CLIENT_CATEGORY_LIST_REQUEST_MODEL_KEY)
	public List<LabelVO> populateClientCategory() {

		List<LabelVO> labelList = new ArrayList<LabelVO>();
		LabelVO labelVO = new LabelVO();

		labelList.add(labelVO);

		List<ClientCategoryVO> clientCategoryVOs = this.nonClientPersonRegisterDelegate.getClientCategory(Constants.PERSON); 

		for (ClientCategoryVO categoryVO : clientCategoryVOs) {
			
			labelVO = getMapper().map(categoryVO, LabelVO.class);
			labelList.add(labelVO);
		}

		return labelList;
	}

	@ModelAttribute(ConstantsAdmin.NON_CLIENT_PERSON_REGISTER_ROLES_LIST_REQUEST_MODEL_KEY)
	public List<LabelVO> populateNonClientRolesListModel() {

		List<LabelVO> labelList = new ArrayList<LabelVO>();
		LabelVO labelVO;
		List<ClientRoleVO> clientRoleVOs = utilityDelegate.getClientRoleList(Constants.PERSON, true);

		for (ClientRoleVO roleVO : clientRoleVOs) {

			labelVO = getMapper().map(roleVO, LabelVO.class);
			labelList.add(labelVO);

		}

		return labelList;
	}

	@ModelAttribute(ConstantsAdmin.COUNTRY_LIST_REQUEST_MODEL_KEY)
	public List<LabelVO> populateCountryListModel(Locale locale) {

		List<LabelVO> labelList = new ArrayList<LabelVO>();
		LabelVO labelVO = new LabelVO();
		labelList.add(labelVO);

		List<CountryVO> countryVOs = utilityDelegate.getCountryList(locale.toString());

		for (CountryVO countryVO : countryVOs) {
			labelVO = getMapper().map(countryVO, LabelVO.class);
			labelList.add(labelVO);
		}

		return labelList;
	}

	@RequestMapping(value = "/city.json", method = RequestMethod.GET)
	@ResponseBody
	public List<LabelVO> getCity(HttpServletRequest request,
			@RequestParam(value = "contryCode", required = false) String countryCode) {

		List<LabelVO> labelList = new ArrayList<LabelVO>();
		List<CityVO> cityVOs = utilityDelegate.getCityListByCountryCode(countryCode, RequestContextUtils.getLocale(request)
				.toString());
		LabelVO labelVO;
		labelVO = new LabelVO();
		
		labelList.add(labelVO);
		
		for (CityVO cityVO : cityVOs) {
			labelVO = getMapper().map(cityVO, LabelVO.class);
			labelList.add(labelVO);
		}

		return labelList;
	}

	@ModelAttribute(ConstantsAdmin.NATIONALITY_LIST_REQUEST_MODEL_KEY)
	public List<LabelVO> populateNationalityListModel(HttpServletRequest request) {

		List<LabelVO> labelList = new ArrayList<LabelVO>();

		LabelVO labelVO;

		List<CountryVO> countryVOs = utilityDelegate.getCountryList(RequestContextUtils.getLocale(request).toString());
		// TODO: How to map this thing
		for (CountryVO countryVO : countryVOs) {
			labelVO = new LabelVO();
			labelVO.setId(countryVO.getStrCountryCode());
			labelVO.setLabelAr(countryVO.getStrCountryNationalityArb());
			labelVO.setLabelEn(countryVO.getStrCountryNationality());
			labelList.add(labelVO);

		}

		return labelList;
	}

	@ModelAttribute(ConstantsAdmin.NON_CLIENT_REGISTRATION_UPLOADDOCUMENT_TYPE_MODEL_KEY)
	public List<LabelVO> populateRegisterNonClientPersonUploadDocumentType() {

		List<LabelVO> labelList = new ArrayList<LabelVO>();
		String strAttachmentTypeUser = ConstantsAdmin.PROCESS_CODE_NON_CLIENT_PERSON_REGISTRATION;
		List<AttachmentTypeVO> attachmentTypeVOs = attachmentTypeDelegate.getAttachmentType(strAttachmentTypeUser);

		LabelVO labelVO;

		for (AttachmentTypeVO attachmentTypeVO : attachmentTypeVOs) {
			labelVO = getMapper().map(attachmentTypeVO, LabelVO.class);
			labelList.add(labelVO);
		}

		return labelList;
	}

	@ModelAttribute(ConstantsAdmin.NON_CLIENT_PERSON_REGISTER_VISA_TYPE_LIST_REQUEST_MODEL_KEY)
	public List<LabelVO> populateVisaTypeListModel() {

		List<LabelVO> labelList = new ArrayList<LabelVO>();

		LabelVO labelVO;
		LabelVO blanklabel = new LabelVO();
		blanklabel.setId("");
		blanklabel.setLabelAr("");
		blanklabel.setLabelEn("");

		List<VisaTypeVO> visatypeVOs = utilityDelegate.getVisaType();
		labelList.add(blanklabel);

		for (VisaTypeVO visatypeVO : visatypeVOs) {
			labelVO = getMapper().map(visatypeVO, LabelVO.class);
			labelList.add(labelVO);

		}

		return labelList;
	}

	/**
	 * Custom handler for displaying the form, i.e.: GET requests for
	 * /nonclient/person/register/personalinfo/form.
	 * 
	 * @see #form(NonClientPersonRegisterPersonalInfo)
	 * @see WEB-INF/jsp/nonclient/person/register/personalinfo/form.jsp
	 */

	@RequestMapping(value = "/form.htm", method = RequestMethod.GET)
	public void form(
			@ModelAttribute(value = ConstantsAdmin.NON_CLIENT_PERSON_REGISTER_REQUEST_MODEL_KEY) NonClientPersonRegisterPersonalInfo nonClientPersonRegisterPersonalInfo) {

	}

	@RequestMapping(params = { "Upload" }, method = RequestMethod.POST, value = "/form.htm")
	public String uploadForm(
			HttpServletRequest request,
			SessionStatus status,
			@ModelAttribute(value = ConstantsAdmin.NON_CLIENT_PERSON_REGISTER_REQUEST_MODEL_KEY) @Valid NonClientPersonRegisterPersonalInfo nonClientPersonRegisterPersonalInfo,
			BindingResult errors) throws Exception {

		boolean isUpload = WebUtils.hasSubmitParameter(request, ConstantsAdmin.UPLOAD_BUTTON);
		try {

			if (isUpload) {
				if (errors.hasErrors()) {
					return ViewUtils.DEFAULT_VIEW;
				} else {
					if (uploadDocuments(request, status, nonClientPersonRegisterPersonalInfo)) {
	
						request.setAttribute(ConstantsAdmin.SUCCESS_PARAM, nonClientPersonRegisterPersonalInfo.getStrUploadDocumentType());
						return ViewUtils.DEFAULT_VIEW;
					} else {
						request.setAttribute(ConstantsAdmin.ERROR_PARAM, ConstantsAdmin.ERROR_PARAM);
						String[] messageArgs = new String[] { getMessageSource().getMessage("label.company.uploaddocuments", null,
								RequestContextUtils.getLocale(request)) };
						errors.reject("error.file.not.selected", messageArgs, null);
					}
				}
			}
			
		} catch (DuplicateMemberException dme) {
			
			request.setAttribute(ConstantsAdmin.ERROR_PARAM, ConstantsAdmin.ERROR_PARAM);
			String[] messageArgs = new String[] { getMessageSource().getMessage("label.company.uploaddocuments", null,
					RequestContextUtils.getLocale(request)) };

			errors.reject("error.repeat", messageArgs, null);
			
		}catch (Exception e) 
		{
			e.printStackTrace();
		}

			
		return ViewUtils.DEFAULT_VIEW;
	}

	public boolean uploadDocuments(
			HttpServletRequest request,
			SessionStatus status,
			@ModelAttribute(value = ConstantsAdmin.NON_CLIENT_PERSON_REGISTER_REQUEST_MODEL_KEY) @Valid NonClientPersonRegisterPersonalInfo nonClientPersonRegisterPersonalInfo)
			throws Exception {

		MultipartHttpServletRequest multipartRequest = (MultipartHttpServletRequest) request;
		MultiValueMap<String, MultipartFile> files = multipartRequest.getMultiFileMap();

		boolean uploaded = false;

		if (files != null) {

			@SuppressWarnings("rawtypes")
			Iterator iter = files.keySet().iterator();

			while (iter.hasNext()) {
				String str = (String) iter.next();
				List<MultipartFile> fileList = files.get(str);

				for (MultipartFile mpf : fileList) {
					if (!(fileList.get(0)).isEmpty()) {
						String tempFileName = "" + System.currentTimeMillis();
						String fileExtension = FilenameUtils
								.getExtension(StringUtils.trim(mpf.getOriginalFilename()));

						String personFolderPath = propertyConstants.get(ConstantsAdmin.UPLOAD_PERSON_FILES_PATH_KEY);
						String tempFolderPath = propertyConstants.get(ConstantsAdmin.TEMP_UPLOAD_FILES_PATH_KEY);

						File uploadedFile = new File(tempFolderPath + tempFileName + "." + fileExtension);
						FileOutputStream fos = new FileOutputStream(uploadedFile);
						fos.write(mpf.getBytes());
						fos.close();
						uploaded = true;

						UploadDocumentVO documentVO = new UploadDocumentVO();

						documentVO.setStrName(FilenameUtils.getName(mpf.getOriginalFilename()));
						documentVO.setURL(personFolderPath + nonClientPersonRegisterPersonalInfo.getStrNonClientPersonNameENG()
								+ FilenameUtils.getName(mpf.getOriginalFilename()));
						documentVO.setStrUploadDocumentType(nonClientPersonRegisterPersonalInfo.getStrUploadDocumentType());
						documentVO.setStrTempFileName(tempFileName + "." + fileExtension);
						documentVO.setStrExtension(fileExtension);

						List<UploadDocumentVO> arrDocumentVOs;

						if (nonClientPersonRegisterPersonalInfo.getArrDocumentVOs() == null) {
							arrDocumentVOs = new ArrayList<UploadDocumentVO>();
						} else
							arrDocumentVOs = nonClientPersonRegisterPersonalInfo.getArrDocumentVOs();
						
						for (UploadDocumentVO uploadDocumentVO : arrDocumentVOs) {
							if (uploadDocumentVO.getStrUploadDocumentType().equals(documentVO.getStrUploadDocumentType())) {
								throw new DuplicateMemberException("Cannnot Add again");
							}
						}
						
						// Checking if the file already exists
						/*
						 * int i = -1; boolean found = false; for
						 * (UploadDocumentVO vo : arrDocumentVOs) { if
						 * (vo.getStrUploadDocumentType().endsWith(
						 * nonClientPersonRegisterPersonalInfo
						 * .getStrUploadDocumentType())) { found = true; break;
						 * } ++i; }
						 * 
						 * if (found) arrDocumentVOs.set(i, documentVO); else
						 */
						arrDocumentVOs.add(documentVO);

						nonClientPersonRegisterPersonalInfo.setArrDocumentVOs(arrDocumentVOs);

						/*
						 * if (documentType.equals("LEASE_COPY")) {
						 * nonClientPersonRegisterPersonalInfo
						 * .setStrLeaseCopyName(strFinalVersion);
						 * nonClientPersonRegisterPersonalInfo
						 * .setStrLeaseCopyURL(Constants.UPLOAD_FILES_PATH +
						 * StringUtils
						 * .trimAllWhitespace(mpf.getOriginalFilename()));
						 * 
						 * } else { nonClientPersonRegisterPersonalInfo.
						 * setStrContractCopyName(strFinalVersion);
						 * nonClientPersonRegisterPersonalInfo
						 * .setStrContractCopyURL(Constants.UPLOAD_FILES_PATH +
						 * StringUtils
						 * .trimAllWhitespace(mpf.getOriginalFilename())); }
						 */
					}
				}
			}

		}

		return uploaded;
	}

	@RequestMapping(params = { "next" }, method = RequestMethod.POST, value = "/form.htm")
	public NonClientPersonRegisterPersonalInfo populateRegisterNonClientPersonPreviewSubmitModel(
			HttpServletRequest request,
			SessionStatus status,
			@ModelAttribute(value = ConstantsAdmin.NON_CLIENT_PERSON_REGISTER_REQUEST_MODEL_KEY) @Valid NonClientPersonRegisterPersonalInfo nonClientPersonRegisterPersonalInfo,
			BindingResult errors, Model model) {

		if (null != nonClientPersonRegisterPersonalInfo.getArrDocumentVOs()) {
			if (nonClientPersonRegisterPersonalInfo.getArrDocumentVOs().size() < 1) {
				request.setAttribute(ConstantsAdmin.UPLOAD_PARAM, ConstantsAdmin.UPLOAD_PARAM);
				String[] messageArgs = new String[] { getMessageSource().getMessage("label.company.uploaddocuments", null,
						RequestContextUtils.getLocale(request)) };
				errors.reject("error.file.upload", messageArgs, null);
			} else {
				request.setAttribute(ConstantsAdmin.PREVIEW_PARAM, ConstantsAdmin.PREVIEW_PARAM);
			}
		} else {
			request.setAttribute(ConstantsAdmin.UPLOAD_PARAM, ConstantsAdmin.UPLOAD_PARAM);
			String[] messageArgs = new String[] { getMessageSource().getMessage("label.company.uploaddocuments", null,
					RequestContextUtils.getLocale(request)) };
			errors.reject("error.file.upload", messageArgs, null);
		}

		return nonClientPersonRegisterPersonalInfo;

	}

	/**
	 * Custom handler for displaying the form, i.e.:POST requests for
	 * /nonclient/person/register/personalinfo/form.jsp
	 * 
	 * @see #form(NonClientCompanyRegistrationLicenseInfo)
	 * @see WEB-INF/jsp/nonclient/person/register/personalinfo/form.jsp
	 */

	@RequestMapping(method = RequestMethod.POST, value = "/form.htm")
	public String form(
			HttpServletRequest request,
			SessionStatus status,
			@ModelAttribute(value = ConstantsAdmin.NON_CLIENT_PERSON_REGISTER_REQUEST_MODEL_KEY) @Valid NonClientPersonRegisterPersonalInfo nonClientPersonRegisterPersonalInfo,
			BindingResult errors) throws Exception {

		boolean isSubmit = WebUtils.hasSubmitParameter(request, ConstantsAdmin.SUBMIT_BUTTON);

		if (isSubmit) {
			if (errors.hasErrors()) {
				return ViewUtils.DEFAULT_VIEW;
			} else {
				for (UploadDocumentVO documentVO : nonClientPersonRegisterPersonalInfo.getArrDocumentVOs()) {

					String personFolderPath = propertyConstants.get(ConstantsAdmin.UPLOAD_PERSON_FILES_PATH_KEY);
					String tempFolderPath = propertyConstants.get(ConstantsAdmin.TEMP_UPLOAD_FILES_PATH_KEY);

					File uploadedFile = new File(tempFolderPath + documentVO.getStrTempFileName());
					File uploadFile = new File(personFolderPath
							+ nonClientPersonRegisterPersonalInfo.getStrNonClientPersonNameENG() + documentVO.getStrName());

					FileUtils.copyFile(uploadedFile, uploadFile);
				}

				NonClientPersonVO nonClientPersonVO = new NonClientPersonVO();
				getMapper().map(nonClientPersonRegisterPersonalInfo, nonClientPersonVO);
				
				nonClientPersonVO.setStrCpCategory(nonClientPersonRegisterPersonalInfo.getStrCategory());
				
				// TODO Mapper for Roles
				List<ClientRoleVO> list = new ArrayList<ClientRoleVO>();
				ClientRoleVO clientRoleVO;
				for (Integer role : nonClientPersonRegisterPersonalInfo.getiClientRole()) {

					clientRoleVO = new ClientRoleVO();
					clientRoleVO.setStrCrId(role.toString());

					list.add(clientRoleVO);
				}
				nonClientPersonVO.setArrClientRole(list);
				//

				//nonClientPersonVO.setStrProcessCode(ConstantsAdmin.PROCESS_CODE_NON_CLIENT_PERSON_REGISTRATION);
				nonClientPersonVO.setProcessCode(WFProcessType.NON_CLIENT_PERSON_REGISTRATION);
				nonClientPersonVO.setStrProcessStep(ConstantsAdmin.PROCESS_STEP_INITIATE_NON_CLIENT_PERSON);
				nonClientPersonVO.setApplicationDate(Calendar.getInstance().getTime());
				nonClientPersonVO.setStrWFinitatedBy(ConstantsAdmin.NON_CLIENT_PERSON_WORK_FLOW_INITIATE);
				nonClientPersonVO.setStrWfStatus(ConstantsCommon.IN_PROGRESS);
				nonClientPersonVO.setStrStatusEn(getMessageSource().getMessage("msg.workflow.status.in.progress", null, Locale.ENGLISH));
				nonClientPersonVO.setStrStatusAr(getMessageSource().getMessage("msg.workflow.status.in.progress", null, new Locale(Constants.LOCALE_ARABIC)));
				nonClientPersonVO.setStrClientType(Constants.PERSON);				

				String refNo = nonClientPersonRegisterDelegate.registerNonClientPerson(nonClientPersonVO);

				Map<String, String> paramMap = new HashMap<String, String>();
				paramMap.put(ConstantsAdmin.REFRENCE_NO, SecurityUtils.encryptQueryParam(refNo));

				return ViewUtils.getRedirect(ViewPath.CONFIRMATION, PageType.SHOW, paramMap);

			}

		} else
			return ViewUtils.DEFAULT_VIEW;

	}

}
